﻿namespace com.net
{
    using com.game;
    using com.game.module.SystemData;
    using com.net.debug;
    using com.net.interfaces;
    using com.u3d.bases.debug;
    using Proto;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Runtime.CompilerServices;

    internal class NetSocket : ISocket
    {
        private byte[] bodyBuffer;
        private readonly LinkedList<byte[]> dataList = new LinkedList<byte[]>();
        private readonly byte[] headBuffer = new byte[2];
        private bool isReceive = true;
        private NetMsgCallback msgCallback;
        private int msgLen;
        private string netStatus = "linkFail";
        private readonly LinkedList<string> netStatusList = new LinkedList<string>();
        private NetStatusCallback statusCallback;
        private TcpClient tcpClient;

        public NetSocket()
        {
            this.tryNum = 1;
            this.tryableNum = 1;
        }

        public void close()
        {
            this.stopReceive();
            if ((this.tcpClient != null) && (this.tcpClient.Client != null))
            {
                this.tcpClient.Client.Close();
                this.tcpClient.Close();
                this.tcpClient = null;
            }
            NetLog.info(this, "-close() 已关闭与服务器连接！");
            this.setNetStatus("linkFail");
            this.bodyBuffer = null;
            this.msgLen = 0;
        }

        public void connect(string ip, int port)
        {
            if ((this.tcpClient != null) && (this.tcpClient.Client != null))
            {
                this.tcpClient.Client.Close();
                this.tcpClient.Close();
                this.tcpClient = null;
            }
            if (!this.connected())
            {
                try
                {
                    this.setNetStatus("linking");
                    this.ip = ip;
                    this.port = port;
                    IPAddress address = IPAddress.Parse(ip);
                    IPEndPoint point = new IPEndPoint(address, port);
                    Log.info(this, string.Concat(new object[] { "-connect() 第", this.tryNum, "次连接服务器 [", point, "] [Start]" }));
                    this.tcpClient = new TcpClient();
                    this.tcpClient.NoDelay = true;
                    this.tcpClient.SendTimeout = 0xbb8;
                    this.tcpClient.ReceiveTimeout = 0xbb8;
                    this.tcpClient.Client.ReceiveBufferSize = 0x19000;
                    this.tcpClient.BeginConnect(address, port, new AsyncCallback(this.ConnectCallBack), this);
                }
                catch (Exception exception)
                {
                    NetLog.error(this, "-connect() 连接服务器异常：" + exception);
                    this.retryConnect();
                }
            }
        }

        private void ConnectCallBack(IAsyncResult asyncresult)
        {
            NetSocket asyncState = asyncresult.AsyncState as NetSocket;
            try
            {
                if ((asyncState.tcpClient.Client != null) && asyncState.tcpClient.Client.Connected)
                {
                    asyncState.tcpClient.EndConnect(asyncresult);
                    NetLog.info(asyncState, string.Concat(new object[] { "-ConnectCallBack()第", asyncState.tryNum, "次连接服务器 [", asyncState.ip, "] [OK]" }));
                    asyncState.startReceive();
                    asyncState.tryNum = 0;
                    asyncState.msgLen = 0;
                    LinkedList<byte[]> dataList = this.dataList;
                    lock (dataList)
                    {
                        this.dataList.Clear();
                    }
                    asyncState.setNetStatus("linkOk");
                    MemoryStream msdata = new MemoryStream();
                    this.send(msdata, 1, 0);
                }
                else
                {
                    NetLog.info(asyncState, string.Concat(new object[] { "-ConnectCallBack()第", asyncState.tryNum, "次连接服务器 [", asyncState.ip, "] [Fail]" }));
                    asyncState.retryConnect();
                }
            }
            catch (Exception exception)
            {
                NetLog.error(asyncState, "-ConnectCallBack() 连接服务器异常：" + exception);
                asyncState.retryConnect();
            }
        }

        public bool connected()
        {
            return ((((this.tcpClient != null) && (this.tcpClient.Client != null)) && this.tcpClient.Client.Connected) && this.netStatus.Equals("linkOk"));
        }

        public int getTryableNum()
        {
            return this.tryableNum;
        }

        public void msgListenner(NetMsgCallback listener)
        {
            this.msgCallback = listener;
        }

        public void retryConnect()
        {
            this.isReceive = false;
            if (this.tryNum < this.tryableNum)
            {
                this.tryNum++;
                this.connect(this.ip, this.port);
            }
            else
            {
                NetLog.error(this, "-retryConnect() 请求网络连接失败");
                this.close();
            }
        }

        private void send(byte[] data)
        {
            if (this.connected())
            {
                try
                {
                    Log.info(this, string.Concat(new object[] { "-Send 成功发送数据 ", data.Length, "bytes:   ServerTimestamp:", ServerTime.Instance.Timestamp }));
                    this.tcpClient.Client.Send(data);
                }
                catch (Exception exception)
                {
                    NetLog.error(this, "-send() 发送数据出错," + exception);
                    this.close();
                }
            }
            else
            {
                NetLog.error(this, "-send()  网络未连接,关闭网络请重新连接");
                this.close();
            }
        }

        public void send(MemoryStream msdata, byte framID, byte wayID)
        {
            this.send(NetData.Encode(msdata, framID, wayID));
        }

        private void sendAnsy(byte[] data)
        {
            if (this.connected())
            {
                try
                {
                    this.tcpClient.Client.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(this.SendCallBack), data);
                }
                catch (Exception exception)
                {
                    NetLog.error(this, "-sendAnsy() 发送数据出错," + exception);
                    this.close();
                }
            }
            else
            {
                NetLog.error(this, "-sendAnsy()  网络未连接,关闭网络请重新连接");
                this.close();
            }
        }

        private void SendCallBack(IAsyncResult asyncresult)
        {
            byte[] asyncState = asyncresult.AsyncState as byte[];
            try
            {
                int num = this.tcpClient.Client.EndSend(asyncresult);
                this.sendNext();
            }
            catch (Exception exception)
            {
                NetLog.error(this, "-SendCallBack() 发送数据失败" + exception.Message);
                this.close();
            }
        }

        private void sendNext()
        {
            LinkedList<byte[]> dataList = this.dataList;
            lock (dataList)
            {
                this.dataList.RemoveFirst();
                if (this.dataList.Count > 0)
                {
                    this.sendAnsy(this.dataList.First.Value);
                }
            }
        }

        private void setNetStatus(string netStatus)
        {
            if ((this.netStatus == null) || !this.netStatus.Equals(netStatus))
            {
                this.netStatus = netStatus;
                LinkedList<string> netStatusList = this.netStatusList;
                lock (netStatusList)
                {
                    if (this.statusCallback != null)
                    {
                        this.netStatusList.AddLast(netStatus);
                    }
                }
            }
        }

        public void setTryableNum(int num)
        {
            this.tryableNum = num;
        }

        private void startReceive()
        {
            this.isReceive = true;
        }

        public void statusListener(NetStatusCallback listener)
        {
            this.statusCallback = listener;
        }

        private void stopReceive()
        {
            this.isReceive = false;
        }

        public void Update()
        {
            LinkedList<string> netStatusList = this.netStatusList;
            lock (netStatusList)
            {
                if ((this.netStatusList.Count > 0) && (this.statusCallback != null))
                {
                    this.statusCallback(this.netStatusList.First.Value);
                    this.netStatusList.RemoveFirst();
                }
            }
            if (this.connected())
            {
                try
                {
                    while (this.tcpClient.Client.Available >= 2)
                    {
                        if (this.msgLen == 0)
                        {
                            this.tcpClient.Client.Receive(this.headBuffer);
                            this.msgLen = ByteUtil.Byte2Int(this.headBuffer);
                            this.bodyBuffer = new byte[this.msgLen];
                        }
                        else
                        {
                            if (this.tcpClient.Client.Available < this.msgLen)
                            {
                                return;
                            }
                            this.tcpClient.Client.Receive(this.bodyBuffer);
                            NetData receiveData = new NetData(this.bodyBuffer);
                            AppNet.main.receiveNetMsg(receiveData);
                            this.bodyBuffer = null;
                            this.msgLen = 0;
                            continue;
                        }
                    }
                }
                catch (Exception exception)
                {
                    NetLog.error(this, "-Update() Socket接收数据出错," + exception);
                    this.close();
                }
            }
            else if (this.netStatus.Equals("linkOk"))
            {
                this.close();
            }
        }

        public string ip { get; set; }

        public int port { get; set; }

        public int tryableNum { get; set; }

        public int tryNum { get; set; }
    }
}

